/****************************************************************************
	This file is part of Basqet.

	Basqet is free software: you can redistribute it and/or modify
	it under the terms of the GNU General Public License as published by
	the Free Software Foundation, either version 3 of the License, or
	(at your option) any later version.

	Basqet is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.

	You should have received a copy of the GNU General Public License
    along with Basqet.  If not, see <http://www.gnu.org/licenses/>.

****************************************************************************/

#include "pagenotewidget.h"
#include "ui_pagenotewidget.h"

#include "pagenotewidgeteventfilter.h"

#include "notedata.h"
#include "textnotedata.h"

#include "commandmanager.h"
#include "cmdchangetextnotegeometry.h"
#include "cmdmovesplitter.h"
#include "cmddeletetextnote.h"
#include "cmdsettag.h"

#include "tagmanager.h"

#include <QEvent>
#include <QMouseEvent>
#include <QPoint>
#include <QLabel>
#include <QBoxLayout>

#include <QtDebug>

PageNoteWidget::PageNoteWidget(QExplicitlySharedDataPointer<NoteData> pNoteData,
							   QExplicitlySharedDataPointer<CommandManager> pCommandManager,
							   QExplicitlySharedDataPointer<TagManager> pTagManager,
							   QWidget *parent /*= 0*/)
	:QWidget(parent),
	mCommandManager(pCommandManager),
	mTagManager(pTagManager),
	mMoveOperation(false),
	mResizeOperation(false),
	m_ui(new Ui::PageNoteWidget),
	mPNoteData(pNoteData),
	mPTextNoteData(dynamic_cast<TextNoteData*> (mPNoteData.data()))
{
    m_ui->setupUi(this);

	// Hide boxes for icons.

	m_ui->pLableBox->setHidden(true);
	m_ui->pSteriotypeBox->setHidden(true);


	m_ui->pHeaderBodySplitter->setSizes(mPTextNoteData->getHeaderBodySliderSizes());

	connect(m_ui->pHeaderBodySplitter, SIGNAL(splitterMoved(int,int)), this, SLOT(splitterMoved(int,int)));

	mGroupBoxFilter = new PageNoteWidgetEventFilter();
	m_ui->groupBox->installEventFilter(mGroupBoxFilter);

	connect(mGroupBoxFilter.data(), SIGNAL(startMouseMoveEvent(QMouseEvent*)), this, SLOT(startMoveOperation(QMouseEvent*)));
	connect(mGroupBoxFilter.data(), SIGNAL(mouseMoveEvent(QMouseEvent*)), this, SLOT(continueMoveOperation(QMouseEvent*)));
	connect(mGroupBoxFilter.data(), SIGNAL(mouseMoveEventEnd(QMouseEvent*)), this, SLOT(endMoveOperation(QMouseEvent*)));

	mTextAreaFilter = new PageNoteWidgetEventFilter();
	m_ui->pNoteText->installEventFilter(mTextAreaFilter);

	connect(mTextAreaFilter.data(), SIGNAL(startMouseMoveEvent(QMouseEvent*)), this, SLOT(startMoveOperation(QMouseEvent*)));
	connect(mTextAreaFilter.data(), SIGNAL(mouseMoveEvent(QMouseEvent*)), this, SLOT(continueMoveOperation(QMouseEvent*)));
	connect(mTextAreaFilter.data(), SIGNAL(mouseMoveEventEnd(QMouseEvent*)), this, SLOT(endMoveOperation(QMouseEvent*)));

	QPoint pos = mPNoteData->getPosition();

	if (!pos.isNull())
	{
		move(pos);
	}

	QSize size = mPNoteData->getSize();

	if (!size.isNull())
	{
		resize(size);
	}
	else
		qDebug() << "Create note: size is NULL";

	// Read the tags

	if (mPTextNoteData)
	{
		QStringList tagList = mPTextNoteData->getTagList();
		foreach (QString tag, tagList)
		{
			tagSet(tag);
		}
	}


	// Read the contents of the object.

	if (mPTextNoteData)
	{
		m_ui->pNoteText->setDocument(mPTextNoteData->getDocument());
		m_ui->pHeaderText->setDocument(mPTextNoteData->getHeaderDocument());

	}

	// Connect to changes in the data-object we reflect.
	connect(mPNoteData.data(), SIGNAL(geometryChanged(QPoint,QSize)), this, SLOT(cmdChangeGeometry(QPoint,QSize)));
	connect(mPNoteData.data(), SIGNAL(removed()), this, SLOT(noteRemoved()));
	connect(mPNoteData.data(), SIGNAL(headerBodySliderResized(const QList<int>&)), this, SLOT(splitterInfo(QList<int>)));

	connect(mPNoteData.data(), SIGNAL(tagChanged(QString,QString)), this, SLOT(tagChanged(QString,QString)));
	connect(mPNoteData.data(), SIGNAL(tagSet(QString)), this, SLOT(tagSet(QString)));
	connect(mPNoteData.data(), SIGNAL(tagCleared(QString)), this, SLOT(tagCleared(QString)));

	// Forward some signals from the TextEditor:
	connect(m_ui->pNoteText, SIGNAL(activated(QObject*,UICapabilities)), this, SLOT(editorActivated(QObject*,UICapabilities)));
	connect(m_ui->pHeaderText, SIGNAL(activated(QObject*,UICapabilities)), this, SLOT(editorActivated(QObject*,UICapabilities)));

}

PageNoteWidget::~PageNoteWidget()
{
    delete m_ui;
}

void PageNoteWidget::noteRemoved()
{
	hide();
	delete this;
}


void PageNoteWidget::cmdChangeGeometry(QPoint pos, QSize size)
{

	if (!pos.isNull())
		move(pos);

	if (size.isValid())
		resize(size);

}

/***************************************************************************/
// Slots
/***************************************************************************/



void PageNoteWidget::editorActivated(QObject *object, UICapabilities capabilities)
{
	mPActiveEditor = dynamic_cast<RichTextEdit*> (object);

	capabilities.setDeletion(true);
	capabilities.setLabeling(true);

	emit activated(this, capabilities);

}

void PageNoteWidget::actionDelete()
{
	qDebug() << "PageNoteWidget::actionDelete";
	CmdDeleteTextNote* pCmd = new CmdDeleteTextNote(mPNoteData);

	mCommandManager->Push(pCmd);

}


/***************************************************************************/
/* Labeling.                                                               */
/***************************************************************************/

/***************************************************************************/
/** Act on responce from UI. Create command and post to command manager.
  *
  */
void PageNoteWidget::actionSetLable(QString label, const QIcon& icon)
{
	Q_UNUSED(icon);

	CmdSetTag* command = new CmdSetTag(mPNoteData.data(), label);
	mCommandManager->Push(command);

}


/***************************************************************************/
/** Act on changes in NoteData. Show right icons.
  *
  */

void PageNoteWidget::tagSet(QString tag)
{
	qDebug() << "tagSet:" << tag;

	QLabel* pLabel = new QLabel();
	pLabel->setObjectName(tag);

	QIcon icon = mTagManager->getIcon(tag);
	pLabel->setPixmap(icon.pixmap(24, 24));

	m_ui->pLableBox->setHidden(false);

	if (!m_ui->pLableBox->layout())
	{
		m_ui->pLableBox->setLayout(new QBoxLayout(QBoxLayout::TopToBottom));
		m_ui->pLableBox->layout()->setAlignment(Qt::AlignTop);
	}

	m_ui->pLableBox->layout()->addWidget(pLabel);

}

void PageNoteWidget::tagCleared(QString tag)
{
	qDebug() << "tagCleared:" << tag;

	QLabel* pLabel = new QLabel();
	pLabel->setObjectName(tag);

	QLabel * existingLabel = m_ui->pLableBox->findChild<QLabel*>(tag);
	if (existingLabel)
	{
		int index = m_ui->pLableBox->layout()->indexOf(existingLabel);
		m_ui->pLableBox->layout()->takeAt(index);
		delete existingLabel;

		if (m_ui->pLableBox->layout()->count() == 0)
			m_ui->pLableBox->setHidden(true);

	}
}

void PageNoteWidget::tagChanged(QString oldTag, QString newTag)
{
	qDebug() << "tagChanged:" << oldTag << " to " << newTag;

	QLabel * existingLabel = m_ui->pLableBox->findChild<QLabel*>(oldTag);
	if (existingLabel)
	{
		existingLabel->setObjectName(newTag);
		QIcon icon = mTagManager->getIcon(newTag);
		existingLabel->setPixmap(icon.pixmap(24, 24));

	}
}



/***************************************************************************/
// Event handlers
/***************************************************************************/

/***************************************************************************/

void PageNoteWidget::changeEvent(QEvent *e)
{
    QWidget::changeEvent(e);
    switch (e->type()) {
    case QEvent::LanguageChange:
        m_ui->retranslateUi(this);
        break;
    default:
        break;
    }
}


void PageNoteWidget::focusInEvent(QFocusEvent * event)
{

	QWidget::focusInEvent(event);

}


/***************************************************************************/

void PageNoteWidget::activateInput()
{
	m_ui->pNoteText->setFocus();
}


/***************************************************************************/
/** A move-operation is started, i.e. the user have pressed a button and
  * moves the mouse.
  * This can be either a move of the note or a resize, al depending of
  * where in the widget the user have pressed.
  *
  * It is a resize-operation if upper-left or lower-right corner is clicked,
  * it is a move-operation otherwise.
  */
void PageNoteWidget::startMoveOperation(QMouseEvent* event)
{
	mResizeOperation = false;
	mMoveOperation   = false;

	// Check for resize-operation.
	if (event->pos().x() <=  10 && event->pos().y() <= 10)
	{
		mResizeOperation = true;
		mMoveOperation   = true;

	}
	else if (event->pos().x() >=  (width() - 30) && event->pos().y() >= (height() - 30))
	{
		mResizeOperation = true;
	}
	else
	{
		mMoveOperation = true;
	}


	mWidgetResizeOrgin = size();
	mMoveOrigin = event->globalPos();
	mMoveWidgetOrgin = pos();

}

void PageNoteWidget::continueMoveOperation(QMouseEvent* event)
{
	QList <int>		splitterSizesBefore;
	QList <int>		splitterSizesAfter;

	if (mResizeOperation && !mMoveOperation)
	{

		QSize	newSize;

		newSize.setWidth(event->globalPos().x() - mMoveOrigin.x() + mWidgetResizeOrgin.width());
		newSize.setHeight(event->globalPos().y() - mMoveOrigin.y() + mWidgetResizeOrgin.height());


		// Manage the resize while keeping the splitter så that the header-part is not
		// rezised.
		splitterSizesBefore = m_ui->pHeaderBodySplitter->sizes();
		resize(newSize);
		splitterSizesAfter  = m_ui->pHeaderBodySplitter->sizes();

		if (splitterSizesBefore.size() > 1 && splitterSizesAfter.size() > 1)
		{
			splitterSizesBefore[1] = splitterSizesAfter[0] + splitterSizesAfter[1] - splitterSizesBefore[0];
			m_ui->pHeaderBodySplitter->setSizes(splitterSizesBefore);
		}


	}
	else if (mResizeOperation && mMoveOperation)
	{
		QSize	newSize;

		newSize.setWidth(mMoveOrigin.x() - event->globalPos().x()  + mWidgetResizeOrgin.width());
		newSize.setHeight(mMoveOrigin.y() - event->globalPos().y() + mWidgetResizeOrgin.height());

		if (newSize.height() < minimumHeight())
			newSize.setHeight(minimumHeight());

		if (newSize.width() < minimumWidth())
			newSize.setWidth(minimumWidth());

		// Manage the resize while keeping the splitter så that the header-part is not
		// rezised.
		splitterSizesBefore = m_ui->pHeaderBodySplitter->sizes();
		resize(newSize);
		splitterSizesAfter  = m_ui->pHeaderBodySplitter->sizes();

		if (splitterSizesBefore.size() > 1 && splitterSizesAfter.size() > 1)
		{
			splitterSizesBefore[1] = splitterSizesAfter[0] + splitterSizesAfter[1] - splitterSizesBefore[0];
			m_ui->pHeaderBodySplitter->setSizes(splitterSizesBefore);
		}

	}


	if (mMoveOperation)
	{
		move(event->globalPos() - mMoveOrigin + mMoveWidgetOrgin);
	}


}

void PageNoteWidget::endMoveOperation(QMouseEvent* event)
{
	continueMoveOperation(event);

	CmdChangeNoteGeometry*	pCommand  = 0;
	TextNoteData* textNote = dynamic_cast<TextNoteData* >(mPNoteData.data());

	if (textNote)
	{
		CmdChangeTextNoteGeometry* pTextCommand = new CmdChangeTextNoteGeometry(textNote);
		pCommand = pTextCommand;

		pTextCommand->moveSplitter(m_ui->pHeaderBodySplitter->sizes());

	}
	else
	{
		qDebug() << "Resizing somthing not a textnote.";
		pCommand = new CmdChangeNoteGeometry(mPNoteData.data());
	}

	pCommand->changeSize(size());
	pCommand->changePos(pos());

	mCommandManager->Push(pCommand);

}


void PageNoteWidget::splitterMoved(int pos, int index)
{
	Q_UNUSED(pos);
	Q_UNUSED(index);

	CmdMoveSplitter* pCommand = new CmdMoveSplitter(dynamic_cast<TextNoteData*> (mPNoteData.data()));

	pCommand->setNewSizes(m_ui->pHeaderBodySplitter->sizes());

	mCommandManager->Push(pCommand);

}


void PageNoteWidget::splitterInfo(const QList <int>& sizes)
{

	m_ui->pHeaderBodySplitter->setSizes(sizes);

}


/***************************************************************************/
/* Formating Slots.                                                        */
/***************************************************************************/

void PageNoteWidget::setBold()
{
	if (mPActiveEditor)
		mPActiveEditor->setBold();
}

void PageNoteWidget::setItalic()
{
	if (mPActiveEditor)
		mPActiveEditor->setItalic();
}

void PageNoteWidget::setUnderline()
{
	if (mPActiveEditor)
		mPActiveEditor->setUnderline();
}

void PageNoteWidget::setStrikethrough()
{
	if (mPActiveEditor)
		mPActiveEditor->setStrikethrough();
}

void PageNoteWidget::incFontSize()
{

	if (mPActiveEditor)
		mPActiveEditor->incFontSize();

}


void PageNoteWidget::decFontSize()
{
	if (mPActiveEditor)
		mPActiveEditor->decFontSize();

}


void PageNoteWidget::setLeft()
{
	if (mPActiveEditor)
		mPActiveEditor->setLeft();
}


void PageNoteWidget::setRight()
{
	if (mPActiveEditor)
		mPActiveEditor->setRight();
}


void PageNoteWidget::setMid()
{
	if (mPActiveEditor)
		mPActiveEditor->setMid();
}



